using System;
using Gtk;
using Gdk;
using System.IO;

public partial class MainWindow: Gtk.Window
{	
	public delegate void StringHandler(string aMessage);
	
	public MainWindow (): base (Gtk.WindowType.Toplevel)
	{
		Build ();
		
		_logViewerMainTitle = this.Title;
		_timers = new System.Collections.Generic.Dictionary<Guid, System.Threading.Timer>();
	}
			
	void OnDeleteEvent (object sender, DeleteEventArgs a)
	{
		Application.Quit ();
		a.RetVal = true;
	}

	string _logViewerMainTitle;
	System.IO.FileSystemWatcher _fileSystemWatcher;
	int _updateCount;
	string _fileName;
	System.Collections.Generic.Dictionary<Guid, System.Threading.Timer> _timers;
	
	protected virtual void OnOpenActionActivated (object sender, System.EventArgs e)
	{
 		// Reset the logTreeView and change the window back to original size
     	int width, height;
	    this.GetDefaultSize( out width, out height );
	    this.Resize( width, height );
	     
	    txtvwMain.Buffer.Text = "";
		
		_updateCount = 0;
	     
	    // Create and display a fileChooserDialog
	    using (FileChooserDialog chooser = new FileChooserDialog(
	        "Please select a logfile to view ...",
	        this,
	        FileChooserAction.Open,
	        "Cancel", ResponseType.Cancel,
	        "Open", ResponseType.Accept ))
		{
			try
			{
		   		if( chooser.Run() == ( int )ResponseType.Accept )
		     	{
					_fileName = chooser.Filename;
					
			        // Set the MainWindow Title to the filename.
			        this.Title = _logViewerMainTitle + " -- " + _fileName;
			        
			        // Make the MainWindow bigger to accomodate the text in the logTextView
			        this.Resize( 640, 480 );

					UpdateLog(_fileName);
					
					string lpath = System.IO.Path.GetDirectoryName(chooser.Filename);
					string lfilename = System.IO.Path.GetFileName(chooser.Filename);
					
					_fileSystemWatcher = new System.IO.FileSystemWatcher(
						     lpath,
						     "*.*"
					     );
					
					statusbar1.Push(1, "::" + lpath + "::" + lfilename + "::");
					
					_fileSystemWatcher.Changed += new System.IO.FileSystemEventHandler(OnChanged);
					_fileSystemWatcher.Deleted += new System.IO.FileSystemEventHandler(OnChanged);

					_fileSystemWatcher.EnableRaisingEvents = true;
		    	} // end if
			}
			finally
			{
				chooser.Destroy();
			}
		}	
	}

	public void UpdateLog(string aLogFileName)
	{
//		lock(this)
//		{
//			Gdk.Threads.Enter();
			try
			{
				_updateCount++;
				statusbar1.Push(0, _updateCount.ToString());
				
				txtvwMain.Buffer.Text = System.IO.File.ReadAllText(aLogFileName);
				
				scrolledwindow1.Vadjustment.Value = scrolledwindow1.Vadjustment.Upper;
			}
			catch (Exception ex)
			{
				txtvwMain.Buffer.Text = ex.ToString();
			}
			finally
			{
//				Gdk.Threads.Leave();
			}
//		}
	}
	
	private void OnTimer(object state)
	{
		lock(this)
		{
			System.Threading.Timer ltimer;
			
			if (_timers.TryGetValue((Guid)state, out ltimer))
			{
				_timers.Remove((Guid)state);
				ltimer.Dispose();
				ltimer = null;
			}
		}
			
		Gtk.Application.Invoke(new EventHandler(CallUpdateLog));
	}				                                           

	private void CallUpdateLog(object source, EventArgs e)
    {
		UpdateLog(_fileName);
	}

	private void OnChanged(object source, FileSystemEventArgs e)
    {
		if (e.ChangeType == WatcherChangeTypes.Changed)
		{
			//UpdateLog(_fileName);
			Gtk.Application.Invoke(new EventHandler(CallUpdateLog));
			
			ScheduleUpdateLog(500);
			ScheduleUpdateLog(1000);
			ScheduleUpdateLog(1500);
		}
	}

	public void ScheduleUpdateLog(int aMSec)
	{
			lock(this)
			{
				Guid lguid = Guid.NewGuid();
					
				System.Threading.Timer ltimer = 
					new System.Threading.Timer(
					    new System.Threading.TimerCallback(OnTimer),
					    lguid, 
					    aMSec, 
					    System.Threading.Timeout.Infinite
					);
				
				_timers[lguid] = ltimer;
			}
	}
	
	protected virtual void OnCloseActionActivated (object sender, System.EventArgs e)
	{
		if (_fileSystemWatcher != null)
		{
			_fileSystemWatcher.Dispose();
			_fileSystemWatcher = null;
		}
			
		// Reset the logTreeView and change the window back to original size
		int width, height;
		this.GetDefaultSize( out width, out height );
		this.Resize( width, height );
		
		txtvwMain.Buffer.Text = "";
		
		// Change the MainWindow Title back to the default.
		this.Title = _logViewerMainTitle;
	}

	protected virtual void OnExitActionActivated (object sender, System.EventArgs e)
	{
		if (_fileSystemWatcher != null)
		{
			_fileSystemWatcher.Dispose();
			_fileSystemWatcher = null;
		}

		Application.Quit();
	}

	protected virtual void OnAboutActionActivated (object sender, System.EventArgs e)
	{
		// Create a new About dialog
		using (AboutDialog about = new AboutDialog())
		{	
			try
			{
				// Change the Dialog's properties to the appropriate values.
				about.ProgramName = _logViewerMainTitle + "(" + _updateCount.ToString() + ")";
				
				about.Version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
				
				// Show the Dialog and pass it control
				about.Run();
			}
			finally
			{
				about.Destroy();
			}
		}
	}

	protected virtual void OnUpdateActionActivated (object sender, System.EventArgs e)
	{
		//UpdateLog(_fileName);
		Gtk.Application.Invoke(new EventHandler(CallUpdateLog));
	}
}